package spms.data.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.type.Alias;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import spms.data.dao.BaseDao;
import spms.data.service.BaseService;
import spms.util.Page;

import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class BaseServiceImpl<T> implements BaseService<T> {
    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    BaseDao<T> baseDao;


    @Override
    public int count(String tableName) {
        return baseDao.count(tableName);
    }

    @Override
    public List<T> findAll(Class<T> clazz) throws Exception {

        String value = clazz.getAnnotation(Alias.class).value().toLowerCase();

        if (!ObjectUtils.isEmpty(value)) {
            String tableName = value.toLowerCase();
            logger.info("开始调用findAll(Class<T> clazz)查询表：{}", tableName);
            List<T> result = baseDao.findAll(null, value);
            result = parseResult(result, clazz);
            logger.info("调用findAll(Class<T> clazz)查询表：{} ，查询结束，返回：{}", tableName, result);
            return result;
        }

        throw new Exception("the entity object" + clazz.getName() + " has no alias name," +
                "this name must be same with the target table name(case insensitive)");
    }

    @Override
    public List<T> findAll(T t) throws Exception {
        Alias alias = t.getClass().getAnnotation(Alias.class);

        if (!ObjectUtils.isEmpty(alias.value())) {
            StringBuilder sb = new StringBuilder();
            JSONObject job = JSONObject.parseObject(JSONObject.toJSONString(t));

            for (String key : job.keySet()) {
                String val = parseParam(job.get(key));
                sb.append(key.toLowerCase()).append("=").append(val).append(" and");
            }
            String sql = sb.length() > 3 ? sb.substring(0, sb.length() - 3) : null;
            logger.info("开始调用findAll(T t)查询表：{}", alias.value().toLowerCase());
            List<T> result = baseDao.findAll(sql, alias.value().toLowerCase());
            result = parseResult(result, t.getClass());
            logger.info("调用findAll(T t)查询表：{} ，查询结束，返回：{}", alias.value().toLowerCase(), result);
            return result;
        }

        throw new Exception("the entity object" + t.getClass().getName() + " has no alias name," +
                "this name must be same with the target table name(case insensitive)");

    }

    @Override
    public Page<T> findPage(int pageNum, int pageSize, Class<T> clazz) throws Exception {

        Alias alias = clazz.getAnnotation(Alias.class);

        if (!ObjectUtils.isEmpty(alias.value())) {
            logger.info("开始调用findPage(int pageNum, int pageSize,Class<T> clazz)查询表：{}", alias.value().toLowerCase());
            List<T> result = baseDao.findPage(pageNum, pageSize, alias.value().toLowerCase());
            result = parseResult(result, clazz);
            logger.info("调用findPage(int pageNum, int pageSize,Class<T> clazz)查询表：{} ，查询结束，返回：{}", alias.value().toLowerCase(), result);
            return new Page<>(pageNum, pageSize, count(alias.value().toLowerCase()), result);
        }

        throw new Exception("the entity object" + clazz.getName() + " has no alias name," +
                "this name must be same with the target table name(case insensitive)");
    }

    public String parseParam(Object obj) {
        if (obj instanceof String) {
            return "'" + obj + "'";
        } else if (obj instanceof Integer) {
            return obj.toString();
        } else if (obj instanceof Timestamp) {
            return "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Timestamp) obj) + "'";
        } else if (obj instanceof Date) {
            return "'" + new SimpleDateFormat("yyyy-MM-dd").format((Date) obj) + "'";
        }

        return null;
    }

    public List<T> parseResult(List<T> result, Class<?> clazz) {
        List<T> list = new ArrayList<>();
        List<Field> fields = Arrays.asList(clazz.getDeclaredFields());

        result.forEach(item -> {
            Map map = (HashMap) item;
            Map temp = new HashMap();

            fields.forEach(field -> {
                String name = field.getName();
                if (map.containsKey(name.toLowerCase())) {
                    temp.put(name, map.get(name.toLowerCase()));
                } else {
                    temp.put(name, null);
                }
            });
            list.add((T) temp);
        });
        return list;
    }

}
